package com.orifine.sql.simple;

import java.util.List;

import org.apache.ibatis.jdbc.SelectBuilder;

public class SimpleSelectBuilder {
	private SimpleSelectSql selectSQL = new SimpleSelectSql();
	private static final String AND = ") \nAND (";
	private static final String OR = ") \nOR (";

	public SimpleSelectBuilder() {
		SelectBuilder.BEGIN();
	}

	public SimpleSelectBuilder select(String columns) {
		selectSQL.select.add(columns);
		return this;
	}
	
	public SimpleSelectBuilder select(String column, String alias){
		select(column + " AS '" + alias + "'");
		return this;
	}
	
	public SimpleSelectBuilder select(String from, String column, String alias){
		select(from + "." + column + " AS '" + alias + "'");
		return this;
	}

	public SimpleSelectBuilder selectDistinct(String columns) {
		selectSQL.distinct = true;
		return this;
	}

	public SimpleSelectBuilder from(String table) {
		selectSQL.from.add(table);
		return this;
	}
	
	public SimpleSelectBuilder from(String table, String alias){
		from(table + " AS '" + alias + "'");
		return this;
	}

	public SimpleSelectBuilder join(String join) {
		selectSQL.join.add(join);
		return this;
	}

	public SimpleSelectBuilder innerJoin(String join) {
		selectSQL.innerJoin.add(join);
		return this;
	}

	public SimpleSelectBuilder leftOuterJoin(String join) {
		selectSQL.leftOuterJoin.add(join);
		return this;
	}
	
	public SimpleSelectBuilder leftOuterJoin(String join, String on){
		leftOuterJoin(join + " ON " + on);
		return this;
	}

	public SimpleSelectBuilder rightOuterJoin(String join) {
		selectSQL.rightOuterJoin.add(join);
		return this;
	}

	public SimpleSelectBuilder outerJoin(String join) {
		selectSQL.outerJoin.add(join);
		return this;
	}

	public SimpleSelectBuilder where(String conditions) {
		selectSQL.where.add(conditions);
		selectSQL.lastList = selectSQL.where;
		return this;
	}

	public SimpleSelectBuilder or() {
		selectSQL.lastList.add(OR);
		return this;
	}

	public SimpleSelectBuilder and() {
		selectSQL.lastList.add(AND);
		return this;
	}

	public SimpleSelectBuilder groupBy(String columns) {
		selectSQL.groupBy.add(columns);
		return this;
	}

	public SimpleSelectBuilder having(String conditions) {
		selectSQL.having.add(conditions);
		selectSQL.lastList = selectSQL.having;
		return this;
	}

	public SimpleSelectBuilder orderBy(String columns) {
		selectSQL.orderBy.add(columns);
		return this;
	}
	
	public SimpleSelectBuilder orderBy(String column, String sort){
		orderBy(column + " " + sort);
		return this;
	}
	
	public SimpleSelectBuilder orderBy(String from, String column, String sort){
		orderBy(from + "." + column + " " + sort);
		return this;
	}
	
	public SimpleSelectBuilder limit(Integer offset, Integer rows) {
		selectSQL.offset = offset;
		selectSQL.rows = rows;
		return this;
	}

	private void selectClause(StringBuilder builder, String keyword, List<String> parts, String open, String close, String conjunction) {
		if (!parts.isEmpty()) {
			if (builder.length() > 0)
				builder.append("\n");
			builder.append(keyword);
			builder.append(" ");
			builder.append(open);
			String last = "________";
			for (int i = 0, n = parts.size(); i < n; i++) {
				String part = parts.get(i);
				if (i > 0 && !part.equals(AND) && !part.equals(OR)
						&& !last.equals(AND) && !last.equals(OR)) {
					builder.append(conjunction);
				}
				builder.append(part);
				last = part;
			}
			builder.append(close);
		}
	}
	
	private void limitClause(StringBuilder builder){
		if (selectSQL.rows != null){
			if(builder.length() > 0) builder.append("\n");
			if(selectSQL.offset != null){
				builder.append("LIMIT").append(" ").append(selectSQL.offset).append(",").append(selectSQL.rows);
			} else {
				builder.append("LIMIT").append(" ").append(selectSQL.rows);
			}
		}
	}

	public String toString() {
		StringBuilder builder = new StringBuilder();
		if (selectSQL.distinct) {
			selectClause(builder, "SELECT DISTINCT", selectSQL.select, "", "",
					", ");
		} else {
			selectClause(builder, "SELECT", selectSQL.select, "", "", ", ");
		}

		selectClause(builder, "FROM", selectSQL.from, "", "", ", ");
		selectClause(builder, "JOIN", selectSQL.join, "", "", "JOIN");
		selectClause(builder, "INNER JOIN", selectSQL.innerJoin, "", "",
				"\nINNER JOIN ");
		selectClause(builder, "OUTER JOIN", selectSQL.outerJoin, "", "",
				"\nOUTER JOIN ");
		selectClause(builder, "LEFT OUTER JOIN", selectSQL.leftOuterJoin, "",
				"", "\nLEFT OUTER JOIN ");
		selectClause(builder, "RIGHT OUTER JOIN", selectSQL.rightOuterJoin, "",
				"", "\nRIGHT OUTER JOIN ");
		selectClause(builder, "WHERE", selectSQL.where, "(", ")", " AND ");
		selectClause(builder, "GROUP BY", selectSQL.groupBy, "", "", ", ");
		selectClause(builder, "HAVING", selectSQL.having, "(", ")", " AND ");
		selectClause(builder, "ORDER BY", selectSQL.orderBy, "", "", ", ");
		limitClause(builder);
		return builder.toString();
	}
}
